package com.loren.demo10.aspect;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

@Slf4j
@Aspect
@Component
@RequiredArgsConstructor
public class TransactionAspect {

    private final TransactionTemplate transactionTemplate;

    @Around("execution(* com.loren.demo10.controller.*.*(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        HttpServletRequest request = this.getHttpServletRequest();
        if (request == null) {
            return joinPoint.proceed();
        }
        String requestMethod = request.getMethod();
        String requestUri = request.getRequestURI();
        log.info("requestMethod = {}, requestUri = {}", requestMethod, requestUri);
        return this.transactionTemplate.execute(status -> {
            Object result;
            try {
                result = joinPoint.proceed();
            } catch (Throwable e) {
                log.error("transaction aspect around error", e);
                throw new RuntimeException(e.getMessage());
            }
            return result;
        });
    }

    private HttpServletRequest getHttpServletRequest() {
        RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
        return servletRequestAttributes == null ? null : servletRequestAttributes.getRequest();
    }
}
